const chokidar = require('chokidar');

const { createChallengeNode } = require('./create-challenge-nodes');

exports.sourceNodes = function sourceChallengesSourceNodes(
  { actions, reporter },
  pluginOptions
) {
  const { source, onSourceChange, curriculumPath } = pluginOptions;
  if (typeof source !== 'function') {
    reporter.panic(`
    "source" is a required option for fcc-source-challenges. It must be a
    function that delivers challenge objects to the plugin
    `);
  }
  if (typeof onSourceChange !== 'function') {
    reporter.panic(`
    "onSourceChange" is a required option for fcc-source-challenges. It must be
    a function that delivers a new challenge object to the plugin
    `);
  }
  if (typeof curriculumPath !== 'string') {
    reporter.panic(`
    "curriculumPath" is a required option for fcc-source-challenges. It must be
    a path to a curriculum directory
    `);
  }
  const { createNode } = actions;
  const watcher = chokidar.watch(curriculumPath, {
    ignored: /(^|[\/\\])\../,
    persistent: true,
    usePolling: true
  });

  watcher.on('change', filePath =>
    /\.md$/.test(filePath)
      ? onSourceChange(filePath)
          .then(challenge => {
            reporter.info(
              `
File changed at ${filePath}, replacing challengeNode id ${challenge.id}
              `
            );
            createVisibleChallenge(challenge);
          })
          .catch(e =>
            reporter.error(`fcc-replace-challenge

  ${e.message}

  `)
          )
      : null
  );

  function sourceAndCreateNodes() {
    return source()
      .then(challenges => Promise.all(challenges))
      .then(challenges =>
        challenges.map(challenge => createVisibleChallenge(challenge))
      )
      .catch(e =>
        reporter.panic(`fcc-source-challenges

  ${e.message}

  `)
      );
  }

  function createVisibleChallenge(challenge) {
    if (challenge.superBlock.toLowerCase() === 'certificates') return;
    createNode(createChallengeNode(challenge, reporter));
  }

  return new Promise((resolve, reject) => {
    watcher.on('ready', () => sourceAndCreateNodes().then(resolve, reject));
  });
};
